package view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

public class SlidingMenu extends ViewGroup {
    final private int STATE_MENU_CLOSE_IDLE = 3;
    final private int STATE_MENU_OPENING = 4;
    final private int STATE_MENU_OPEN_IDLE = 1;
    final private int STATE_MENU_CLOSING = 5;
    protected int menuWidthPercentage = 75;
    /**
     * 中间View左上角的X坐标
     */
    protected int position = 0;
    private int animationDuration = 400;
    private boolean blockChildTouchEvent;
    private boolean disableSlide;
    private float firstX, firstY;
    /**
     * 当前中间View滑动的位置
     */
    private int lastPosition;
    /**
     * 左边View的宽度
     */
    private int leftBound;
    private SlidingStateListener listener;
    private View mainView;
    private View menuView;
    private OnTouchOutOfMenuListener onTouchOutOfMenuListener;
    private Scroller scroller;
    /**
     * 是否拦截触屏事件
     */
    private boolean slideDistanceCheckFlag;
    private int slidingState = STATE_MENU_CLOSE_IDLE;
    private boolean startFromEdge;
    private boolean trigerFromEdge;
    private ViewConfiguration viewConfiguration;

    public SlidingMenu(Context context) {
        super(context);
        init(context);
    }

    private void init(Context c) {
        scroller = new Scroller(c);
        viewConfiguration = ViewConfiguration.get(c);
    }

    public SlidingMenu(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public void disapbleSlide() {
        disableSlide = true;
    }

    public boolean isMenuOpened() {
        return position != getMeasuredWidth();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (disableSlide && slidingState == STATE_MENU_CLOSE_IDLE) {
            return false;
        }
        if (slidingState == STATE_MENU_OPENING || slidingState == STATE_MENU_OPEN_IDLE || slidingState == STATE_MENU_CLOSING) {//菜单左侧未遮蔽区域屏蔽点击事件
            if (ev.getX() < position) {
                blockChildTouchEvent = true;
            } else {
                blockChildTouchEvent = false;
            }
        }

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                trigerTouchOutOfMenuBound(ev);
                firstX = ev.getX();
                firstY = ev.getY();
                lastPosition = position;
                slideDistanceCheckFlag = false;
                startFromEdge = firstX < viewConfiguration.getScaledEdgeSlop() * 2 || firstX > getMeasuredWidth() - 2 * viewConfiguration.getScaledEdgeSlop();
                break;
            case MotionEvent.ACTION_MOVE:
                if (slidingState == STATE_MENU_CLOSE_IDLE && trigerFromEdge && !startFromEdge) {
                    return false;
                }
                if (!slideDistanceCheckFlag) {
                    float dx = ev.getX() - firstX;
                    float dy = ev.getY() - firstY;
                    if (Math.abs(dx) + Math.abs(dy) > viewConfiguration.getScaledTouchSlop() && Math.abs(dx) > Math.abs(dy)) {
                        slideDistanceCheckFlag = true;
                    }
                }
        }
        //        handleTouchEvent = slideDistanceCheckFlag || blockChildTouchEvent;
        return blockChildTouchEvent || slideDistanceCheckFlag;
    }
    //    private boolean handleTouchEvent;

    private void trigerTouchOutOfMenuBound(MotionEvent ev) {
        if (slidingState == STATE_MENU_OPEN_IDLE) {
            if (ev.getX() < leftBound) {
                if (null != onTouchOutOfMenuListener) {
                    onTouchOutOfMenuListener.onTouchOutOfMenuBound();
                }
            }
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        drawChild(canvas, mainView, 0);

        int alpha = (int) (200 * (1 - (1f * position - leftBound) / menuView.getMeasuredWidth()));
        canvas.drawColor(Color.argb(alpha, 0, 0, 0));
        drawChild(canvas, menuView, 0);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        layoutChildren();
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //		System.out.println("SlidingFrame onTouchEvent()");
        if (disableSlide && slidingState == STATE_MENU_CLOSE_IDLE) {
            return false;
        }
        if (blockChildTouchEvent) {
            closeMenu();
            return true;
        }
        //        if(!handleTouchEvent){
        //            return false;
        //        }
        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:
                smoothScroll();
                return false;
            case MotionEvent.ACTION_DOWN://onInterceptTouchEvent 返回true跳到这里
                if (!(slidingState == STATE_MENU_CLOSE_IDLE && trigerFromEdge)) {
                    if (!scroller.isFinished()) {
                        scroller.forceFinished(true);
                    }
                    firstX = ev.getX();
                    return true;
                } else {
                    if (startFromEdge) {
                        if (!scroller.isFinished()) {
                            scroller.forceFinished(true);
                        }
                        firstX = ev.getX();
                        return true;
                    } else {
                        return false;
                    }

                }
            case MotionEvent.ACTION_MOVE:
                if (!scroller.isFinished()) {
                    scroller.forceFinished(true);
                }
                float distanceX = ev.getX() - firstX;
                float dx = position - lastPosition - distanceX;
                if (dx < 1 & dx > -1) {
                    return false;
                }
                //			System.out.println("position="+position);
                if (slidingState == STATE_MENU_OPEN_IDLE && distanceX < 0) {
                    return true;
                }
                position = (int) (lastPosition + distanceX);//dx>0 往左滑动
                if (position < leftBound) {
                    position = leftBound;
                    slidingState = STATE_MENU_OPEN_IDLE;
                } else if (position > getMeasuredWidth()) {
                    position = getMeasuredWidth();
                    slidingState = STATE_MENU_CLOSE_IDLE;
                } else {
                    if (dx > 0) {
                        slidingState = STATE_MENU_OPENING;
                    } else {
                        slidingState = STATE_MENU_CLOSING;
                    }
                }
                layoutChildren();
                postInvalidate();
                return true;
        }
        return false;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        position = w;
    }

    @Override
    public void computeScroll() {
        int interval = 2;
        if (scroller.computeScrollOffset()) {
            position = scroller.getCurrX();
            if (slidingState == STATE_MENU_OPENING && position <= leftBound + interval) {
                position = leftBound;
                scroller.forceFinished(true);
                slidingState = STATE_MENU_OPEN_IDLE;
                if (null != listener) {
                    listener.onMenuOpen();
                }
            }
            if (slidingState == STATE_MENU_CLOSING && position > getMeasuredWidth() - interval) {
                scroller.forceFinished(true);
                position = getMeasuredWidth();
                slidingState = STATE_MENU_CLOSE_IDLE;
                blockChildTouchEvent = false;
                if (null != listener) {
                    listener.onMenuClose();
                }
            }
            layoutChildren();
            postInvalidate();//不调用可能看不到滚动效果，不要换成invalidate()
        } else {
            if (position == 0) {
                blockChildTouchEvent = false;
                slidingState = STATE_MENU_CLOSE_IDLE;
            }
        }
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mainView = getChildAt(0);
        menuView = getChildAt(1);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
        mainView.measure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(width, height);
        menuView.measure(MeasureSpec.makeMeasureSpec(width * menuWidthPercentage / 100, MeasureSpec.EXACTLY), heightMeasureSpec);
        leftBound = width - (width * menuWidthPercentage / 100);
    }

    @SuppressLint("NewApi")
    protected void layoutChildren() {
        mainView.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
        menuView.layout(position, 0, menuView.getMeasuredWidth() + position, getMeasuredHeight());
    }

    /**
     * 如果不在中间则滑动到中间
     */
    public void closeMenu() {
        if (position < getMeasuredWidth()) {
            scroller.forceFinished(true);
            slidingState = STATE_MENU_CLOSING;
            smoothScroll();
        }
    }

    //    @Override
    //    protected void dispatchDraw(Canvas canvas) {
    //        drawChild(canvas, mainView, 0);
    //
    ////        float menuScale = (0.8f+0.2f*position/ leftBound);
    ////        canvas.save();
    ////        canvas.scale(menuScale, menuScale, 0, getMeasuredHeight()/2);
    ////        drawChild(canvas, menuView, 0);
    ////        canvas.restore();
    //        int alpha = position * 230 / leftBound;
    //        canvas.drawColor(Color.argb(alpha, 0, 0, 0));
    //        drawChild(canvas, menuView, 0);
    ////        float scale = 1 - 1f * position / (3 * getMeasuredWidth());
    ////        canvas.scale(scale, scale, getMeasuredWidth(), getMeasuredHeight() / 2);
    ////        drawChild(canvas, mainView, 0);
    //    }

    private void smoothScroll() {
        switch (slidingState) {
            case STATE_MENU_OPENING:
                scroller.startScroll(position, 0, leftBound - position, 0, animationDuration);
                break;
            case STATE_MENU_CLOSING:
                scroller.startScroll(position, 0, getMeasuredWidth() - position, 0, animationDuration);
                break;
        }
        postInvalidate();//不调用看不到滚动效果
    }

    /**
     * 在中间状态时，调用此函数会滑动到右侧。
     */
    public void openMenu() {
        //        if (slidingState == STATE_MENU_CLOSE_IDLE) {
        scroller.forceFinished(true);
        slidingState = STATE_MENU_OPENING;
        smoothScroll();
        //        }
    }

    /**
     * 设置动画持续时间，单位毫秒
     */
    public void setAnimationDuration(int duration) {
        animationDuration = duration;
    }

    /**
     * @param listener 当滑动停止时的回调，左侧停下，右侧停下，中间停下
     */
    public void setSlidingStateListener(SlidingStateListener listener) {
        this.listener = listener;
    }

    /**
     * 是否从边缘滑动才触发侧滑
     *
     * @param trigerFromEdge
     */
    public void setTrigerFromEdge(boolean trigerFromEdge) {
        this.trigerFromEdge = trigerFromEdge;
    }

    /**
     * 当left的LayoutParams的宽度为MathParent时设置此参数有效
     *
     * @param percentage 1~100,不调用此方法则根据View的LayoutParams来设置，如果没有设置LayoutParams则高度MatchParent，宽度WrapContent
     */
    public void setWidthPercentage(int percentage) {
        menuWidthPercentage = percentage;
        if (menuWidthPercentage > 100 || menuWidthPercentage < 0) {
            throw new IllegalAccessError("percentage 范围 1~100");
        }
    }

    public interface OnTouchOutOfMenuListener {
        void onTouchOutOfMenuBound();
    }

    /**
     * 当滑动停止时的回调，左侧停下，右侧停下，中间停下
     */
    public interface SlidingStateListener {
        /**
         * 滑动到中间停下
         */
        void onMenuClose();

        /**
         * 滑动到右侧停下
         */
        void onMenuOpen();
    }
}